/**
 * Program   :   LogAspect.java
 * Author    :   shadow guo
 * Create    :   2013-6-15 上午2:49:18
 *
 * Copyright 2008 by Tongfu Information Technology Co. Ltd
 * All rights reserved.
 *
 * This software is the confidential and proprietary information
 * of Tongfu Information Technology Co. Ltd. ("Confidential Information").  You
 * shall not disclose such Confidential Information and shall use
 * it only in accordance with the terms of the license agreement
 * you entered into with Tongfu Information Technology Co. Ltd.
 * 
 */
package com.tongfusoft.web.core.aop;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.ResourceBundle;

import ognl.Ognl;
import ognl.OgnlException;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;

import com.opensymphony.xwork2.ActionContext;
import com.tongfusoft.utils.ReflectionUtils;
import com.tongfusoft.utils.UIDGeneratorService;
import com.tongfusoft.web.core.Constant;
import com.tongfusoft.web.core.annotation.LogDesc;
import com.tongfusoft.web.core.data.BaseData;
import com.tongfusoft.web.core.data.TLogs;
import com.tongfusoft.web.core.data.User;
import com.tongfusoft.web.core.service.ILogService;
import com.tongfusoft.web.core.service.ISecurityService;

@Aspect
public class LogAspect {
	private static final Map<String, String> PREFIX = new HashMap<String, String>();

	private static String RECORD_MODEL = "simple";

	private static String BATCH_OPERATOR = "批量"; 
	
	static {
		PREFIX.put("add", "新增");
		PREFIX.put("update", "修改");
		PREFIX.put("remove", "删除");
		PREFIX.put("down", "下载");
		PREFIX.put("saveFile", "上传");
		PREFIX.put("export","导出");

		ResourceBundle rb = ResourceBundle.getBundle("commons-logging");
		if (StringUtils.isNotEmpty(rb.getString("com.tongfusoft.log"))) {
			RECORD_MODEL = rb.getString("com.tongfusoft.log");
		}
	}

	/**
	 * Logger for this class
	 */
	private static final Log logger = LogFactory.getLog(LogAspect.class);

	private ILogService logService;
	private ISecurityService securityService;

	public ILogService getLogService() {
		return logService;
	}

	public void setLogService(ILogService logService) {
		this.logService = logService;
	}

	public ISecurityService getSecurityService() {
		return securityService;
	}

	public void setSecurityService(ISecurityService securityService) {
		this.securityService = securityService;
	}

	@Pointcut("execution(* com.tongfusoft..*.service..*.add*(..)) || execution(* com.tongfusoft..*.service..*.update*(..)) || execution(* com.tongfusoft..*.service..*.remove*(..)) || execution(* com.tongfusoft..*.service..*.saveFile(..)) || execution(* com.tongfusoft..*.service..*.downLoadFileInfo(..))")
	public void pointcut() {
	}

	// 方法执行前调用
	@Before("pointcut()")
	public void before(JoinPoint joinPoint) {
		if (logger.isDebugEnabled()) {
			logger.debug(joinPoint.getSignature().getName() + " before");
		}
	}

	/**
	 * 获取Log信息
	 * 
	 * @param joinPoint
	 * @param e
	 * @return
	 */
	private TLogs getLog(JoinPoint joinPoint, Exception e) {
		TLogs log = new TLogs();

		User user = this.getRecordUser();

		log.setLogId(UIDGeneratorService.getUUID());
		log.setCreatedBy(user.getPkValue());
		log.setOperName(user.getUserDisplayName());
		log.setOperType(getOperType(joinPoint.getSignature().getName()));

		log.setMethodName(joinPoint.getTarget().getClass().getName() + "."
				+ joinPoint.getSignature().getName());

		// 根据注解获取业务显示内容
		log.setLogContent(getBusinessContent(joinPoint));

		if (e != null) {
			log.setOperResult("0");
		} else {
			log.setOperResult("1");
		}

		// 根据参数获取后台记录内容
		if (RECORD_MODEL.equals("simple")) {
			log.setParamsContent("");
		} else {
			log.setParamsContent(getOperatorContent(joinPoint));
		}

		if (e != null) {
			log.setParamsContent(log.getParamsContent() + ",Exception:"
					+ e.getMessage());
		}

		return log;
	}

	@AfterReturning("pointcut()")
	public void after(JoinPoint joinPoint) {
		if (logger.isDebugEnabled()) {
			logger.debug(joinPoint.getSignature().getName() + " after");
		}

		// 判断参数
		if (joinPoint.getArgs() == null) {// 没有参数
			return;
		}

		TLogs log = this.getLog(joinPoint, null);

		this.getLogService().log(log);
	}

	// 方法运行出现异常时调用
	@AfterThrowing(pointcut = "pointcut()", throwing = "ex")
	public void afterThrowing(JoinPoint joinPoint, Exception ex) {
		if (logger.isDebugEnabled()) {
			logger.debug(joinPoint.getSignature().getName() + " afterThrowing");
		}

		TLogs log = this.getLog(joinPoint, ex);
		this.getLogService().log(log);
	}

	/**
	 * 获取操作类型
	 * 
	 * @param methodName
	 * @return
	 */
	private String getOperType(String methodName) {
		Iterator<Entry<String, String>> iter = PREFIX.entrySet().iterator();
		while (iter.hasNext()) {
			Entry<String, String> entry = iter.next();
			if (StringUtils.startsWith(methodName, entry.getKey())) {
				return entry.getKey();
			}
		}

		return "";
	}

	/**
	 * 获取操作类型描述
	 * 
	 * @param methodName
	 * @return
	 */
	private String getOperTypeName(String methodName) {
		Iterator<Entry<String, String>> iter = PREFIX.entrySet().iterator();
		while (iter.hasNext()) {
			Entry<String, String> entry = iter.next();
			if (StringUtils.startsWith(methodName, entry.getKey())) {
				return entry.getValue();
			}
		}

		return "";

	}

	/**
	 * 获取记录用户信息
	 * 
	 * @return
	 */
	private User getRecordUser() {
		if (SecurityContextHolder.getContext() == null) {
			return null;
		}

		if (SecurityContextHolder.getContext().getAuthentication() == null) {
			return null;
		}

		UserDetails userDetails = (UserDetails) SecurityContextHolder
				.getContext().getAuthentication().getPrincipal();

		if (userDetails == null) {
			return null;
		}

		// 获取登录名
		String userName = userDetails.getUsername();

		if (userName == null || userName.equals("")) {
			return null;
		}

		return this.getSecurityService().getUserInfo(userName);
	}

	private Class[] getParamTypeClass(Object[] params) {
		Class[] clsParams = null;
		if (params != null && params.length > 0) {
			clsParams = new Class[params.length];
			for (int i = 0; i < clsParams.length; i++) {
				clsParams[i] = params[i].getClass();
			}
		}
		return clsParams;
	}

	private String getExpressionValue(Object obj, String expression) {
		try {
			return (String)Ognl.getValue(expression, obj);
		} catch (OgnlException ex) {
			logger.error(expression + ", error:" + ex.getMessage());
		}
		
		return "";
	}

	private String getBusinessContentbyServiceAdapter(JoinPoint joinPoint){
		Object[] params = joinPoint.getArgs();
		if (params != null) {
			for (Object obj : params) {
				//单个Object操作
				if (obj instanceof BaseData) {
					BaseData bd = (BaseData) obj;
					if (bd.getClass()
							.isAnnotationPresent(LogDesc.class)) {
						LogDesc annotation = bd.getClass()
								.getAnnotation(LogDesc.class);
						String value = annotation.value();
						String expression = annotation.expression();

						if (StringUtils.isNotEmpty(expression)) {
							return getOperTypeName(joinPoint
									.getSignature().getName())
									+ " "
									+ value
									+ " "
									+ getExpressionValue(bd,expression);
						} else {
							return getOperTypeName(joinPoint
									.getSignature().getName())
									+ " "
									+ value;
						}
					}
				} else if(obj instanceof List) {  //批量操作
					if(obj != null && ((List)obj).size() > 0){
						BaseData bd = (BaseData) ((List)obj).get(0);
						if (bd.getClass()
								.isAnnotationPresent(LogDesc.class)) {
							LogDesc annotation = bd.getClass()
									.getAnnotation(LogDesc.class);
							String value = annotation.value();
							
							return BATCH_OPERATOR + getOperTypeName(joinPoint
									.getSignature().getName())
									+ " "
									+ value;
						}else{
							return BATCH_OPERATOR + getOperTypeName(joinPoint
									.getSignature().getName());
						}
					}
					
				}
			}
		}
		
		return "";
	}
	
	
	/*private String getBusinessContentbyJsonListAction(JoinPoint joinPoint){
		MethodSignature signature = (MethodSignature) joinPoint.getSignature();

		Method method = ReflectionUtils.getDeclaredMethod(
				joinPoint.getTarget(), joinPoint.getSignature().getName(),
				signature.getMethod().getParameterTypes());
		if (method != null && method.isAnnotationPresent(LogDesc.class)) {
			LogDesc annotation = method.getAnnotation(LogDesc.class);
			
			String expression = annotation.expression();
			//action对象的传入值基本为空，需要从request、session中取值
			Map context = ActionContext.getContext().getContextMap();
			String gridKey = getExpressionValue(context,expression);
			if(ListServiceAdapter.LISTRB.getListElement(gridKey) != null){
				return getOperTypeName(joinPoint.getSignature().getName())
						+ " " + annotation.value() + " " + ListServiceAdapter.LISTRB.getListElement(gridKey).getListName();
			}
		}
		
		return "";
	}*/
	
	/**
	 * 获取业务日志内容
	 * 
	 * @return
	 */
	private String getBusinessContent(JoinPoint joinPoint) {
		try {
			Object[] params = joinPoint.getArgs();

			if (StringUtils
					.equals(joinPoint.getTarget().getClass().getName(),
							"com.tongfusoft.web.core.service.impl.ManagementServiceAdapter")) {
				return getBusinessContentbyServiceAdapter(joinPoint);
			}
			
			MethodSignature signature = (MethodSignature) joinPoint.getSignature();

			Method method = ReflectionUtils.getDeclaredMethod(
					joinPoint.getTarget(), joinPoint.getSignature().getName(),
					signature.getMethod().getParameterTypes());
			if (method != null && method.isAnnotationPresent(LogDesc.class)) {
				LogDesc annotation = method.getAnnotation(LogDesc.class);
				
				String expression = annotation.expression();
				if (StringUtils.isNotEmpty(expression)) {
					if(params != null && params.length > 0){
						//service对象基本都有传入值，可以从中取信息
						return getOperTypeName(joinPoint.getSignature().getName())
								+ " " + annotation.value() + " " + getExpressionValue(params[annotation.recordObjIndex()],expression);
					}else{
						//action对象的传入值基本为空，需要从request、session中取值
						Map context = ActionContext.getContext().getContextMap();
						return getOperTypeName(joinPoint.getSignature().getName())
								+ " " + annotation.value() + " " + getExpressionValue(context,expression);
					}
				}else{
					return getOperTypeName(joinPoint.getSignature().getName())
							+ " " + annotation.value();
				}
				
			}

			return getOperTypeName(joinPoint.getSignature().getName());
		} catch (Exception e) {
			logger.error(e);
			return getOperTypeName(joinPoint.getSignature().getName());
		}
	}

	/**
	 * 获取实际操作内容
	 * 
	 * @return
	 */
	private String getOperatorContent(JoinPoint joinPoint) {
		try {
			Object[] params = joinPoint.getArgs();
			if (StringUtils
					.equals(joinPoint.getTarget().getClass().getName(),
							"com.tongfusoft.web.core.service.impl.ManagementServiceAdapter")) {
				for (Object obj : params) {
					if (obj instanceof BaseData) { //单个对象
						return ((BaseData) obj).getJsonStr();
					}else if(obj instanceof List){ //批量操作
						return BATCH_OPERATOR;
					}
				}
			}

			MethodSignature signature = (MethodSignature) joinPoint.getSignature();

			Method method = ReflectionUtils.getDeclaredMethod(
					joinPoint.getTarget(), joinPoint.getSignature().getName(),
					signature.getMethod().getParameterTypes());
			if (method != null && method.isAnnotationPresent(LogDesc.class)) {
				LogDesc annotation = method.getAnnotation(LogDesc.class);
				if (params != null
						&& annotation.recordObjIndex() < params.length) {
					if (params[annotation.recordObjIndex()] instanceof BaseData) {
						return ((BaseData) params[annotation.recordObjIndex()])
								.getJsonStr();
					} else {
						return Constant.OBJECTMAPPER
								.writeValueAsString(params[annotation
										.recordObjIndex()]);
					}
				}
			}

			return "";
		} catch (Exception e) {
			logger.error(e);
			return "";
		}
	}
}
